// TODO: Put into prefs
//const PC_SERVER_ADDR = 'studio.inf.unisi.ch';
const PC_SERVER_ADDR = 'localhost';
const PC_SERVER_PORT = 8765;
const PC_LISTEN_PORT = PC_SERVER_PORT + 1;

var pc_peer_id_counter = 0;

PC.Peer = function() {};

Object.extend(PC.Peer.prototype, PC.Base.prototype);
Object.extend(PC.Peer.prototype, PC.JSON_RPC.prototype);
Object.extend(PC.Peer.prototype, {

  initPeer: function(client) {
    this.initBase();
    this.initJSON_RPC(this.send);
    this.client = client;

    this.msg_buffer = "";
    this.msg_size = -1;

    this.id = pc_peer_id_counter++; // Unique peer ID.
    this.log(this.id + ": Peer initialized...")
  },

  setConnection: function(connection) {
		this.connection = connection;
  },

  connect: function(host, port) {
    this.connection = new CBSConnection();

    this.connection.connect(host, port, null, 
        true, false, null);

    // We always use the async read...
    this.connection.startAsyncRead(this);

    this.log(this.id + ": Connected to peer - " + host);
  },

  // Called when an asynchronous read returns some data.
  // This is an implementation of DJB-Netstrings, which
  // are used to send JSON_RPC messages.
  // PROTOCOL: {"size:{json-object-here},"}
  onStreamDataAvailable: function(request, istream, offset, count) {
    this.msg_buffer += this.connection.readData(0, count);
    this.processMessage();
  },

  // In case we have multiple packets in the msg_buffer this function is used
  // to recursively process the messages.
  processMessage: function() {
    if(this.msg_size == -1) {
      this.getMessageSize();
    }

    if(this.msg_size > 0) { // Have a valid size

      // Wait until we have a complete json object available.
      if(this.msg_buffer.length >= this.msg_size) {
        this.log("process msg buffer [" + this.msg_size + "]:\n" + this.msg_buffer);
        this.jsonHandleMsg( this.msg_buffer.substr(0, this.msg_size) );

        // Cleanup and process recursively in case we have multiple messages
        // waiting in the buffer.
        this.msg_buffer = this.msg_buffer.slice(this.msg_size);
        this.msg_size = -1;
        if(this.msg_buffer.length > 0) { this.processMessage(); }
      }
    }
  },

  // Parse out the size from the beginning of each netstring.
  getMessageSize: function() {
    // Need to figure out the size if this is the start of a new msg.
    var idx = this.msg_buffer.indexOf(':');

    if(idx > -1) { // Make sure the whole number has arrived.
      this.msg_size = parseInt(this.msg_buffer.substr(0,idx));
      this.msg_buffer = this.msg_buffer.slice(idx+1);
      this.log(this.id + ": Msg size = " + this.msg_size);
    }
  }, 

  // Small wrapper to send everything as a netstring.
  send: function(msg) {
    this.log("Sending msg of " + msg.length + " bytes...");
    this.log("Message: \n" + msg);
    this.connection.sendDataNow(msg.length + ':' + msg + ',');
  },

  // TODO: Should probably take ourselves out of some higher level list of
  // currently active peers...
  onStreamClose: function() { 
    this.log(this.id + ": Peer connection has been closed...");
  }
});

// MasterPeer is used to connect to bootstrap a client.
PC.MasterPeer = Class.create();

Object.extend(PC.MasterPeer.prototype, PC.Peer.prototype);
Object.extend(PC.MasterPeer.prototype, {

  initialize: function(client) {
    this.initPeer(client);
  },

  // Get a list of network peers from some node on the network.  The default is
  // to join the "distinguished node", which is a lightweight server.
  requestPeerList: function(observer) {
    this.observer = observer;
    this.connect(PC_SERVER_ADDR, PC_SERVER_PORT);

    var my_data = { 
      ip: "123.123.123.123",
      port: 3214 }; 

    var peer = this;

    var msg = this.jsonRequest("get_peer_list", my_data, 
      function(peer_list, error) {
        peer.log("Got JSON response: " + peer_list.toString());

        peer.log(this.id + ": Received " + peer_list.length + " peers...");
        peer.observer.onStartPeersReceived(peer_list);
      }); 
    msg = msg;
    this.log("Trying to send: " + msg);
    this.send(msg);
  }
});
